<script setup lang="ts">
import { useApiStore } from '@/app/api/apiStore';
import { useUniqueComponentsStore } from '@/app/globalStores/uniqueComponents';
import { dataSizeStr } from '@/utils/fileUtils/dataSizeStr';
import { fileNameWithoutExt, getFileExt, fileNameTruncateKeepingExt } from '@/utils/fileUtils/ext';
import { storeToRefs } from 'pinia';
import { computed, nextTick, ref } from 'vue';

const props = defineProps<{
    uploadedCallback:(fileId:number, fileName:string)=>Promise<boolean>,
    single?:boolean,
    allowExts?:string[],
    guide?:string,
    maxSize?:number,
    showRenameNote?:boolean,
}>();
const api = useApiStore()
const { pop } = storeToRefs(useUniqueComponentsStore())
const maxSize = computed(()=>props.maxSize??10*1000*1000)
interface StagingFile{
    file:File,
    displayName:string,
    displayNameWithoutExt:string,
    editing?:boolean
}

const fileInput = ref<HTMLInputElement>();
const dirInput = ref<HTMLInputElement>();
async function inputChange(e:Event){
    const tar = e.target as HTMLInputElement;
    if(!tar || !tar.files){
        return;
    }
    const newFiles = Array.from(tar.files);
    tar.value='';
    if(newFiles.length>0){
        const sf:StagingFile[] = [];
        for(let i=0;i<newFiles.length;i++){
            let x = newFiles[i];
            const nameTrun = fileNameTruncateKeepingExt(x.name, 8)
            const displayNameWithoutExt = fileNameWithoutExt(x.name)
            if(x.size > maxSize.value){
                pop.value?.show(`<${nameTrun}>尺寸过大`,"failed")
                continue
            }
            const ext = getFileExt(x.name, false, true).toLowerCase();
            if(props.allowExts && !props.allowExts.includes(ext)){
                pop.value?.show(`<${nameTrun}>不支持文件类型`,"failed")
                continue 
            }
            sf.push({
                file:x,
                displayName:x.name,
                displayNameWithoutExt,
            })
        }
        fileList.value.push(...sf);
    }
    if(props.single){
        //只保留最后一个
        if(fileList.value.length>1){
            fileList.value.splice(0,fileList.value.length-1); 
        }
    }
}
function delFile(idx:number){
    fileList.value.splice(idx,1);
}

const fileList = ref<StagingFile[]>([]);

let committing = false;
async function commit(idx:number){
    //防止重复提交
    if(committing){return;}
    committing = true;
    try{
        const target = fileList.value[idx];
        if(!target){return;}
        if(target.file.size > maxSize.value){
            pop.value?.show("文件过大","failed")
            return;
        }
        const abort = new AbortController();//使用一个永不abort的signal，阻止默认的超时机制
        const resp = await api.fileItem.tryCreateFileItem({
            data:target.file,
            fileName:target.displayName,
        }, abort.signal)
        if(resp){
            const callbackRes = await props.uploadedCallback(resp, target.displayName);
            if(callbackRes){
                pop.value?.show("上传成功","success")
                delFile(idx);
            }
        }
    }catch(e){
        pop.value?.show("上传失败","failed")
    }finally{
        committing = false;
    }
}

const stagingInput = ref<HTMLInputElement[]>();
async function startEditingName(f:StagingFile){
    if(f.editing)
        return;
    f.editing = true;
    f.displayNameWithoutExt = fileNameWithoutExt(f.displayName);
    await nextTick();
    let inputs = stagingInput.value;
    if(inputs && inputs.length===1){
        const input = inputs[0];
        input.focus();
        const inputEnterHandler = (e:KeyboardEvent) => {
            if(e.key === "Enter"){
                endEditingName(f);
                input.removeEventListener("keydown", inputEnterHandler)
            }
        }
        input.addEventListener("keydown", inputEnterHandler);
    }
}
function endEditingName(f:StagingFile){
    const fileExt = getFileExt(f.file.name, false, true);
    f.displayName = f.displayNameWithoutExt + fileExt;
    f.editing = false;
}
const randId = Math.random().toString(36).substring(10);
</script>

<template>
    <div class="fileUpload">
        <div class="staging" :class="{single:props.single}">
            <div class="fileItem" v-for="f,i in fileList" :key="f.file.name">
                <div class="fileBody">
                    <div class="itemName" @click="startEditingName(f)">{{ f.displayName }}</div>
                    <div class="itemControl">
                        <div class="fileSize" :style="{backgroundColor:f.file.size>maxSize?'red':''}">{{ dataSizeStr(f.file.size)}}</div>
                        <button class="ok" @click="commit(i)">上传</button>
                        <button class="cancel" @click="delFile(i)">取消</button>
                    </div>
                </div>
                <div class="nameEdit" v-show="f.editing">
                    <div>
                        <input v-model="f.displayNameWithoutExt" ref="stagingInput"/>
                        <button @click="endEditingName(f)" class="ok">OK</button>
                    </div>
                </div>
            </div>
        </div>
        <div class="controls">
            <label :for="`fileInput_${randId}`" class="uploadBtn">
                选择文件
            </label>
            <label :for="`dirInput_${randId}`" v-if="!props.single" class="uploadBtn">
                选择文件夹
            </label>
        </div>
        <input @change="inputChange" ref="fileInput" :id="`fileInput_${randId}`" type="file" multiple/>
        <input @change="inputChange" ref="dirInput" :id="`dirInput_${randId}`" type="file" webkitdirectory>
        <div class="note" v-if="props.guide">{{ props.guide }}</div>
        <div class="note" v-if="showRenameNote">提示：点击文件名可上传前重命名</div>
    </div>
</template>

<style scoped>
.note{
    text-align: center;
    color: #666;
    font-size: 14px;
}
.nameEdit input{
    border: none;
    margin: 2px;
    width: 150px;
}
.nameEdit div{
    display: flex;
    flex-direction: column;
    align-items: center;
}
.nameEdit{
    position: absolute;
    top:32px;left:10px;
    background-color: #eee;
    border:2px solid white;
    padding-left: 10px;
    height: 70px;
    width:170px;
    z-index: 100;
    border-radius: 10px;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items:start;
    color:white;
    box-shadow: black 0px 0px 8px 0px;
}

.itemControl button,.fileSize{
    margin: auto 0px auto 0px;
    padding-top: 0px;
    width: 46px;
    height: 22px;
    line-height: 22px;
    text-align: center;
    border-radius: 2px;
    color:white;
    cursor: pointer;
}
.itemControl{
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap:2px
}
.itemName:hover{
    text-decoration: underline;
}
.itemName{
    overflow:hidden;
    text-overflow: ellipsis;
    cursor: pointer;
}
.fileIcon{
    border-radius: 5px;
    border:2px solid white;
    font-size: small;
    color:white;
    width: 28px;
    height: 28px;
    line-height: 28px;
    text-align: center;
    flex-shrink: 0;
}

.fileBody{
    white-space: nowrap;
    background-color: white;
    border-radius:5px;
    padding: 4px;
    position: relative;
    text-align: center;
    height:50px;
    flex-grow: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}
.fileSize{
    background-color: #666;
    color:white;
    font-size: small;
}
.fileItem{
    margin: 5px 0px 5px 0px;
    padding: 0px 5px 0px 5px;
    height: 60px;
    display: flex;
    align-items: center;
    gap:5px;
    position: relative;
}
.staging.single{
    height: 70px;
    overflow: visible;
}
.staging{
    width: 220px;
    height: 310px;
    background-color: #ddd;
    overflow-y: scroll;
    display: flex;
    flex-direction: column;
    border-radius: 5px;
}
.controls{
    display: flex;
    flex-direction: row;
    gap:5px;
    justify-content: center;
    align-items: center;
    height: 50px;
}
.fileUpload{
    display: flex;
    flex-direction: column;
    width: fit-content;
}
.uploadBtn{
    background-color: cornflowerblue;
    color:white;
    position: relative;
    height: 35px;
    width: 100px;
    border-radius: 5px;
    text-align: center;
    line-height: 35px;
    cursor: pointer;
    transition: 0.5s;
}
.uploadBtn:hover{
    background-color:rgb(76, 125, 217)
}
.fileUpload input[type=file]{
    display: none;
}
.fileUpload{
    margin: 0px auto 0px auto;
}
</style>